package xyz.lwm.lazycat.aop;

import lombok.AllArgsConstructor;
import xyz.lwm.lazycat.annotation.Around;
import xyz.lwm.lazycat.aop.info.MethodInfo;
import xyz.lwm.lazycat.utility.matcher.Matcher;
import xyz.lwm.lazycat.utility.It;
import xyz.lwm.lazycat.utility.reflect.ReflectUtil;

import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;

/**
 * around 注解切面处理, 类上面有 around 注解
 *
 * @author lwm
 * @see xyz.lwm.lazycat.annotation.Around
 */
class AroundTypeAspect implements Aspect {

    private final AtomicReference<Class<? extends InvocationHandler>> handlerClzRef = new AtomicReference<>();

    @Override
    public Matcher<MethodInfo> matcher() {
        return new TypeAroundMatcher(handlerClzRef);
    }

    @Override
    public InvocationHandler interceptor() {
        // dynamic invocation handler
        return It.of(handlerClzRef.get())
                .let(ReflectUtil::newInstance)
                .let(InvocationHandler.class::cast)
                .get();
    }

    @AllArgsConstructor
    private static class TypeAroundMatcher implements Matcher<MethodInfo> {

        private final AtomicReference<Class<? extends InvocationHandler>> handlerClzRef;

        @Override
        public boolean matches(MethodInfo target) {
            return It.of(target.getClassInfo().getAnnotations())
                    .also(a -> handlerClzRef.set(null))
                    .let(a -> a.getAnnotation(Around.class))
                    .let(Around::value).also(handlerClzRef::set)
                    .let(Objects::nonNull).getOr(false);
        }

    }

}
